﻿using Communication.UDPClient;
using Microsoft.Win32;
using Newtonsoft.Json;
using Stylet;
using Stylet.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.UI;
using System.Windows;
using UDPTest.Library.Model;
using UDPTest.Library.Utils;

namespace UDPTest.Pages
{
    public class MainViewModel : Screen
    {
        private readonly IWindowManager _windowManager;
        private readonly IViewFactory _viewFactory;

        public MainViewModel(IWindowManager windowManager, IViewFactory viewFactory)
        {
            _windowManager = windowManager;
            _viewFactory = viewFactory;
        }

        #region 初始化
        protected override void OnViewLoaded()
        {
            base.OnViewLoaded();

            LoadUserConfig();
            LoadSendDataList();
            BindProperties();
        }

        private void LoadUserConfig()
        {
            LocalIP = Properties.Settings.Default.LocalIP;
            LocalPort = Properties.Settings.Default.LocalPort;
            RemoteIP = Properties.Settings.Default.RemoteIP;
            RemotePort = Properties.Settings.Default.RemotePort;

            IsReceivedHex = Properties.Settings.Default.IsReceivedHex;
            IsReceivedText = Properties.Settings.Default.IsReceivedText;
            IsOmitLongStr = Properties.Settings.Default.IsOmitLongStr;

            IsSendHex = Properties.Settings.Default.IsSendHex;
            IsSendText = Properties.Settings.Default.IsSendText;
            IsAppendCRC = Properties.Settings.Default.IsAppendCRC;

            IsShowDataWin = Properties.Settings.Default.IsShowDataWin;
        }

        private void BindProperties()
        {
            this.Bind(s => IsReceivedHex, (o, e) => PropertiesChanged());
            this.Bind(s => IsReceivedText, (o, e) => PropertiesChanged());
            this.Bind(s => IsOmitLongStr, (o, e) => PropertiesChanged());

            this.Bind(s => IsSendHex, (o, e) => PropertiesChanged());
            this.Bind(s => IsSendText, (o, e) => PropertiesChanged());
            this.Bind(s => IsAppendCRC, (o, e) => PropertiesChanged());

            this.Bind(s => IsShowDataWin, (o, e) => PropertiesChanged());

            Task.Run(() =>
            {
                while (true)
                {
                    Thread.Sleep(1000);

                    if (PropertiesHaveChanged)
                    {
                        PropertiesHaveChanged = false;

                        Properties.Settings.Default.IsReceivedHex = IsReceivedHex;
                        Properties.Settings.Default.IsReceivedText = IsReceivedText;
                        Properties.Settings.Default.IsOmitLongStr = IsOmitLongStr;

                        Properties.Settings.Default.IsSendHex = IsSendHex;
                        Properties.Settings.Default.IsSendText = IsSendText;
                        Properties.Settings.Default.IsAppendCRC = IsAppendCRC;

                        Properties.Settings.Default.IsShowDataWin = IsShowDataWin;

                        Properties.Settings.Default.Save();
                    }
                }
            });
        }

        private bool PropertiesHaveChanged;

        private void PropertiesChanged()
        {
            PropertiesHaveChanged = true;
        }

        #endregion

        #region 顶部工具按钮

        public Visibility PropertiesVisibility => IsShowDataWin ? Visibility.Visible : Visibility.Collapsed;
        private bool IsShowDataWin { get; set; }

        public double WindowsWidth { get; set; }

        public void DoMore()
        {
            IsShowDataWin = !IsShowDataWin;
            WindowsWidth += IsShowDataWin ? 350 : -350;
            PropertiesChanged();
        }

        public void Tools()
        {
            var view = _viewFactory.ToolsViewModel();
            _windowManager.ShowWindow(view);
        }

        public void About()
        {
            var view = _viewFactory.AboutViewModel();
            _windowManager.ShowDialog(view);
        }
        #endregion

        #region 连接

        private UDPClient udpClient { get; set; }
        private IPEndPoint remotePoint;

        public string LocalIP { get; set; }
        public int LocalPort { get; set; }
        public string RemoteIP { get; set; }
        public int RemotePort { get; set; }

        public bool IsConnected => udpClient != null;

        public void Connect()
        {
            try
            {
                udpClient = new UDPClient(LocalIP, LocalPort);
                udpClient.UDPMessageReceived += UdpClient_UDPMessageReceived;
                remotePoint = new IPEndPoint(IPAddress.Parse(RemoteIP), RemotePort);

                Properties.Settings.Default.LocalIP = LocalIP;
                Properties.Settings.Default.LocalPort = LocalPort;
                Properties.Settings.Default.RemoteIP = RemoteIP;
                Properties.Settings.Default.RemotePort = RemotePort;
                Properties.Settings.Default.Save();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }

        public void DisConnect()
        {
            udpClient?.CloseUDP();
            udpClient = null;
        }

        public bool CanConnect => !IsConnected;
        public bool CanDisConnect => IsConnected;


        #endregion

        #region 接收

        public string ReceivedTextList { get; set; } = string.Empty;

        public bool IsReceivedHex { get; set; } = true;
        public bool IsReceivedText { get; set; }

        public bool IsOmitLongStr { get; set; }

        private bool IsShowReceivedText { get; set; } = true;
        public Visibility ShowReceivedTextPauseVisibility => IsShowReceivedText ? Visibility.Collapsed : Visibility.Visible;

        private void UdpClient_UDPMessageReceived(UdpStateEventArgs args)
        {
            //Debug.WriteLine($"receive Length={args.buffer.Length}");

            if (!IsShowReceivedText)
            {
                return;
            }

            string datestr;
            if (IsReceivedHex)
            {
                datestr = ConvertHelper.ByteArrayToHexString(args.buffer);
            }
            else
            {
                datestr = Encoding.ASCII.GetString(args.buffer);
            }

            if (IsOmitLongStr && datestr.Length > 50)
            {
                datestr = datestr.Substring(0, 50) + "...";
            }

            string info = $"{(ReceivedTextList.Length != 0 ? "\r\n" : "")}[{DateTime.Now:HH:mm:ss.fff}][From:{args.remoteEndPoint}]({args.buffer.Length:D4}){datestr}";
            ReceivedTextList += info;

            if (ReceivedTextList.Length > 80000)
            {
                ReceivedTextList = "";
            }
        }

        public void ShowReceivedText()
        {
            IsShowReceivedText = true;
        }

        public void NotShowReceivedText()
        {
            IsShowReceivedText = false;
        }

        public bool CanShowReceivedText => !IsShowReceivedText;
        public bool CanNotShowReceivedText => IsShowReceivedText;


        public void ClearReceivedText()
        {
            ReceivedTextList = "";
        }


        #endregion

        #region 发送

        public bool IsSendHex { get; set; } = true;
        public bool IsSendText { get; set; }

        public string SendDataStr { get; set; } = string.Empty;

        public bool IsAppendCRC { get; set; }

        public string SendTextList { get; set; } = string.Empty;

        public void SendDataClick()
        {
            try
            {
                SendData();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"错误：{ex.Message}", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
        }

        private void SendData()
        {
            SendDataStr = SendDataStr.Trim();

            if (IsSendHex)
            {
                if (SendDataStr.Length < 2)
                {
                    throw new Exception("请输入要发送的数据");
                }

                if (IsAppendCRC)
                {
                    var CrcDataStr = SendDataStr + " 00 00";
                    var bytes = ConvertHelper.HexStringToByteArray(CrcDataStr);
                    bytes = ConvertHelper.CalCRC16a(bytes);
                    SendHexData(bytes);
                }
                else
                {
                    var bytes = ConvertHelper.HexStringToByteArray(SendDataStr);
                    SendHexData(bytes);
                }
            }
            else
            {
                if (SendDataStr.Length < 1)
                {
                    throw new Exception("请输入要发送的文本");
                }

                if (IsAppendCRC)
                {
                    var bytes = Encoding.ASCII.GetBytes(SendDataStr);
                    byte[] crcdates = new byte[bytes.Length + 2];
                    Buffer.BlockCopy(bytes, 0, crcdates, 0, bytes.Length);
                    var crcbytes = ConvertHelper.CalCRC16a(crcdates);
                    SendHexData(crcbytes);
                }
                else
                {
                    var bytes = Encoding.ASCII.GetBytes(SendDataStr);
                    SendHexData(bytes);
                }
            }
        }

        private void SendHexData(byte[] buffer)
        {
            if (udpClient != null)
            {
                udpClient.SendData(remotePoint, buffer);

                var datestr = ConvertHelper.ByteArrayToHexString(buffer);
                DateTime now = DateTime.Now;
                string info = $"{(SendTextList.Length != 0 ? "\r\n" : "")}[{now:hh:mm:ss.fff}][TO:{remotePoint}]({buffer.Length:D4}){datestr}";

                SendTextList += info;
                if (SendTextList.Length > 80000)
                {
                    SendTextList = "";
                }
            }
        }


        public int CycleTime { get; set; } = 1000;
        private bool IsCycleSending { get; set; } = false;
        private ManualResetEvent sendManualResetEvent = new ManualResetEvent(false);

        public async void StartCycleSend()
        {
            bool HasError = false;
            string ErrorMessage = "";

            await Task.Run(() =>
            {
                IsCycleSending = true;
                sendManualResetEvent.Reset();
                while (true)
                {
                    if (sendManualResetEvent.WaitOne(CycleTime))
                    {
                        break;
                    }

                    try
                    {
                        SendData();
                    }
                    catch (Exception ex)
                    {
                        HasError = true;
                        ErrorMessage = $"错误：{ex.Message}";
                        break;
                    }
                }
                IsCycleSending = false;
            });

            if (HasError)
            {
                MessageBox.Show(ErrorMessage, "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }

        public void StopCycleSend()
        {
            sendManualResetEvent.Set();
        }

        public bool CanStartCycleSend => !IsCycleSending;
        public bool CanStopCycleSend => IsCycleSending;

        public void ClearSendText()
        {
            SendTextList = "";
        }


        #endregion

        #region 数据

        private readonly string JsonFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SendDataList.json");

        public BindableCollection<SendData> SendDataList { get; set; }
        public SendData SelectedSendData { get; set; }

        private void LoadSendDataList()
        {
            try
            {
                var json = File.ReadAllText(JsonFilePath);
                List<SendData> SendDatas = JsonConvert.DeserializeObject<List<SendData>>(json);
                SendDataList = new BindableCollection<SendData>(SendDatas);
            }
            catch (Exception)
            {
                SendDataList = new BindableCollection<SendData>();
            }

            this.Bind(s => SelectedSendData, (o, e) => SelectedSendDataChanged());
        }

        private void SelectedSendDataChanged()
        {
            if (SelectedSendData != null)
            {
                SendDataStr = SelectedSendData.Data;
                IsSendHex = SelectedSendData.DataType == DataType.Hex;
                IsSendText = SelectedSendData.DataType == DataType.Text;
            }
        }

        public void AddSendData()
        {
            var view = _viewFactory.AddSendDataViewModel();
            if (_windowManager.ShowDialog(view) == true)
            {
                SendDataList.Add(view.SendData);
                SaveSendDataList();
            }
        }

        public void RemoveSendData()
        {
            if (MessageBox.Show("确实要删除该记录吗？", "Question", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                SendDataList.Remove(SelectedSendData);
                SaveSendDataList();
            }
        }

        public bool CanRemoveSendData => SelectedSendData != null;

        private void SaveSendDataList()
        {
            string json = JsonConvert.SerializeObject(SendDataList.ToList());
            File.WriteAllText(JsonFilePath, json);
        }

        public void SendSelectedSendData()
        {
            Task.Run(() =>
            {
                Thread.Sleep(100);
                try
                {
                    if (SelectedSendData != null)
                    {
                        SendData();
                    }

                }
                catch { }
            });
        }


        public void Load()
        {
            OpenFileDialog fileDialog = new OpenFileDialog() { Filter = "*.json|*.json" };

            if (fileDialog.ShowDialog() == true)
            {
                var json = File.ReadAllText(fileDialog.FileName);
                Template template = JsonConvert.DeserializeObject<Template>(json);
                SendDataList = new BindableCollection<SendData>(template.SendDatas);

                LocalIP = template.LocalIP;
                LocalPort=template.LocalPort;
                RemoteIP = template.RemoteIP;
                RemotePort = template.RemotePort;
            }
        }

        public bool CanLoad => !IsConnected;


        public void Save()
        {
            Template template = new Template()
            {
                LocalIP = LocalIP,
                LocalPort = LocalPort,
                RemoteIP = RemoteIP,
                RemotePort = RemotePort,
                SendDatas = SendDataList.ToList(),
            };

            SaveFileDialog fileDialog = new SaveFileDialog()
            {
                Filter = "*.json|*.json"
            };

            if (fileDialog.ShowDialog() == true)
            {
                string json = JsonConvert.SerializeObject(template);
                File.WriteAllText(fileDialog.FileName, json);
            }
        }

        #endregion
    }
}
